#ifndef BLOCK_H
#define BLOCK_H

#include <vector>
#include <queue>
#include <fstream>
#include <set>

#include "utility.h"

class Block
{
	enum Direction {
		Up = 1,
		Down = 2,
		Left = 3,
		Right = 4
	};

	public:
		Block (Coord startingPoint, int blockNum, int distance);

		static const std::vector<Block>& getAllPossibleBlock (int searchedNum);

		Coord getStartingPoint () const {return startingPoint;}

		//Used by isLinkable for linkableBlock search
		void setMaxDistance (int newMaxDistance);

		int getDistanceFromBlock (const Coord& coord) const;

		int getBlockSize () const;
		int countPotentialBlockSize () const;

		const PrimTileMap&							getBlock () const;
		const std::vector<std::pair<const Block*, int>>	getLinkableBlocks () const;
		const std::queue<Block>						getNotLinkableBlocks () const;
		const std::vector<PrimTileMap>&				getHoles ();
		std::set<Coord>								getCoordsInSet() const;
		// TODO: get not just first neighbors.
		std::set<Coord>                      getNeighbors() const;

        // Only works for 1 distance.
        Coord calculateNextLinkingPoint() const;
		static void rebuildAllPossibleBlock (int SearchedNum);
		//it will recalculate the LinkablePoints, must call it in doSteps before every iteration
		void rebuild ();
	private:
		static std::vector<Block> allPossibleBlocksOf0;
		static std::vector<Block> allPossibleBlocksOf1;
		static std::vector<Block> allPossibleBlocksOf2;
		Coord startingPoint;
		int blockNum;
		int blockSize;
		int potentialBlockSize;
		int maxDistance;

		PrimTileMap block;
		PrimTileMap filteredMap;

		std::vector<PrimTileMap> holes;
		std::vector<std::pair<const Block*, int>> linkableBlocks; //link + distance

		bool isWall (Coord coord) const;
		bool isInTheBlock (Coord coord) const;

		void addToQueue (std::queue<Coord>& queue, Coord coord, Direction direction);
		void fillWithLinkables ();

		//I had no idea how to name this function, so it will call a lambda!
		template <typename Lambda>
		void treeTraversal (Lambda function);

		bool isLinkable (const Block& from, const Block& to);

		void reset ();
};

std::vector<Block*>::const_iterator findBlockByStartingPoint(const std::vector<Block*>& blocks,
                                                             const Coord& coord);

std::set<Coord> getCoordsInSet(PrimTileMap &ptm);

#endif // BLOCK_H
